package com.newlink.building.main.service

import android.annotation.SuppressLint
import android.app.*
import android.content.Intent
import android.os.Build
import android.os.Handler
import android.os.IBinder
import android.os.Looper
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import com.alibaba.android.arouter.core.LogisticsCenter
import com.alibaba.android.arouter.launcher.ARouter
import com.newlink.mqtt.mqttv5.IMqttStatusListener
import com.newlink.mqtt.mqttv5.IPublishActionListener
import com.newlink.mqtt.mqttv5.IReceiveActionListener
import com.newlink.building.library_rino.LoopBackManager
import com.newlink.building.library_rino.ConnectionController
import com.google.gson.Gson
import com.newlink.building.common_base.constant.Base_Constant
import com.newlink.building.common_base.constant.NL_Key
import com.newlink.building.common_base.constant.Base_RouterPath
import com.newlink.building.common_base.event.*
import com.newlink.building.common_base.gson.Base_GsonUtils
import com.newlink.building.common_base.model.bean.Base_MqttConnectWrapper
import com.newlink.building.common_base.notifications.NotificationHandler
import com.newlink.building.common_base.utils.NLog
import com.newlink.building.common_base.utils.LogHandlerThread
import com.newlink.building.common_base.utils.MqttDoorOperator.ACK_TIMEOUT
import com.newlink.building.common_base.utils.MqttDoorOperator.MSGTYPE_ALARM_HANDLE_ACK
import com.newlink.building.common_base.utils.MqttDoorOperator.MSGTYPE_ALARM_HANDLE_NOTIFY
import com.newlink.building.common_base.utils.MqttDoorOperator.MSGTYPE_ALARM_NOTIFY
import com.newlink.building.common_base.utils.MqttDoorOperator.MSGTYPE_ARMING_ACK
import com.newlink.building.common_base.utils.MqttDoorOperator.MSGTYPE_OPEN_DOOR_ACK
import com.newlink.building.common_base.utils.NetWorkUtil.isNetworkAvailable
import com.newlink.building.common_base.utils.Base_Preference
import com.newlink.building.main.R
import com.newlink.building.main.other.Module_Main_MainConstants
import com.newlink.building.main.other.Module_Main_MainConstants.COMMAND_MQTT_SUBSCRIBE_TOPIC_CALL_CREATE_CHANNEL_ACK
import com.newlink.building.main.other.Module_Main_MainConstants.COMMAND_MQTT_SUBSCRIBE_TOPIC_CALL_MESSAGE_ACK
import com.newlink.building.main.other.Module_Main_MainConstants.COMMAND_MQTT_SUBSCRIBE_TOPIC_CALL_SIP_ACK
import com.newlink.building.main.other.Module_Main_MainConstants.COMMAND_MQTT_SUBSCRIBE_TOPIC_NOTIFY
import com.newlink.building.main.other.Module_Main_MqttUtils
import com.newlink.building.main.other.Module_Main_SipMessage
import com.newlink.building.main.other.Module_Main_SipMessageUtils
import com.newlink.building.obfuscation.Module_Obfuscation_ObfuscationHelper
import com.newlink.building.obfuscation.Module_Obfuscation_ObfuscationInvoker
import com.newlink.building.compatibility.Api26Compatibility
import com.newlink.building.compatibility.Module_Phone_Compatibility
import com.newlink.building.manager.Module_Phone_VoipController
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.eclipse.paho.mqttv5.client.IMqttToken
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.jetbrains.anko.runOnUiThread
import org.json.JSONObject
import org.linphone.core.Call
import org.linphone.core.Core
import org.linphone.core.CoreListenerStub
import org.linphone.core.Reason
import org.linphone.mediastream.Version
import com.newlink.building.common_base.utils.EnhancedLogger
import com.newlink.building.common_base.utils.*
import kotlinx.coroutines.withContext

private const val TAG: String = "nl_debug"
private const val MSG_RECONNECT: Int = 100_004_001

/**
 * @Author: mqtt
 * @Date: 2023-04-10
 * @Description:
 */
class MqttV5Service : Service(), IReceiveActionListener {

    private var mqttMsgIdArray: MutableSet<String> = mutableSetOf()
    private var mMqttStatusListener: MqttStatusListener
    private var _mqttBean: Base_MqttConnectWrapper? = null
    private var _mRetryTime = 0
    private var mHandler: Handler = Handler(Looper.getMainLooper())
    private var agoraId: Int by Base_Preference(Base_Constant.AGORA_ID_KEY, 0)
    private var agoraAppId: String by Base_Preference(Base_Constant.AGORA_App_ID_KEY, "")
    private var cMessageEvent: Int = TYPE_CALL_SEND_CREATE_CHANNEL_REQUEST_HOME
    private lateinit var mConnectionController: ConnectionController
    private var mTopicList = mutableListOf<String>()
    private var mIsConnecting: Boolean = false

    //当前的callId暂时不考虑多路的情况
    private var currentCallId: String? = null
    private var isForegroundServiceStarted = false

    //缓存call-id和channelName对应关系
    private val mChannelNameMap: MutableMap<String, String> = mutableMapOf()

    //    private var mStopReceiver  = object : BroadcastReceiver() {
//        override fun onReceive(context: Context?, intent: Intent?) {
//            if (intent?.action == Constant.STOP_MQTT_SERVICE) {
//                NLog.e("[MQTTSERVICE] ......... DESTROY SELF")
//                stopSelf()
//            }
//        }
//    }
    //缓存本次去电的Invite消息,用于离线推送及时发送ReInvite
    private var mInviteCallSipBean: CallSipBean? = null
    private var mCancelCallSipBean: CallSipBean? = null
    private var lastConnectTime: Long = 0L
    private var callStartBasicTimeStamp: Long = 0L
    private var fromFcmCall: Boolean = false
    private var needDisconnectMqttV5: Boolean = false
    private var userId: Long by Base_Preference(Base_Constant.USER_ID_KEY, 0L)

    companion object {
        private const val TYPE_OPEN_DOOR: Int = 1
        private const val TYPE_HANDLE_ALARM: Int = 2
        private const val TYPE_CALL_CREATE: Int = 3
        private const val TYPE_CALL_SIP_BODY: Int = 4

        private const val FOREGROUND_ID = 1_011_003
        private const val SERVICE_NOTIF_ID = 1
        private var isServiceRun: Boolean = false

        @Volatile
        private var isTryingConnect: Boolean = false
    }


    init {
        mMqttStatusListener = MqttStatusListener()
        EventBus.getDefault().register(this)
    }

    @SuppressLint("WrongConstant")
    override fun onCreate() {
        super.onCreate()
        Module_Phone_VoipController.get().coreContext.core.addListener(coreListener)
    }


    private val coreListener: CoreListenerStub = object : CoreListenerStub() {
        override fun onLastCallEnded(core: Core) {
            super.onLastCallEnded(core)
        }

        override fun onCallStateChanged(
            core: Core,
            call: Call,
            state: Call.State?,
            message: String,
        ) {
            when (state) {
                Call.State.OutgoingProgress -> {
                    callStartBasicTimeStamp = System.currentTimeMillis()
                    ConnectionController.getInstance(applicationContext)
                        .setBasicTimeStamp(callStartBasicTimeStamp)
                    appendLineBreak(3)
                    saveLog("----------CALL START----------", "SIP")
                    if (call.params.getCustomHeader(NL_Key.CALL_INFO) == NL_Key.EXTRA_MONITOR) {
                        saveLog("★★★★★ Start monitoring ★★★★★", "SIP")
                    } else {
                        if (call.params.isVideoEnabled) {
                            saveLog("★★★★★ Start video call ★★★★★", "SIP")
                        } else {
                            saveLog("★★★★★ Start audio call ★★★★★", "SIP")
                        }
                    }
                    call.callLog.callId?.let { mChannelNameMap.put(it, "") }
                }

                Call.State.IncomingReceived -> {
                    if (mConnectionController.getChannelName() == null) {
                        callStartBasicTimeStamp = System.currentTimeMillis()
                        ConnectionController.getInstance(applicationContext)
                            .setBasicTimeStamp(callStartBasicTimeStamp)
                    }

                    appendLineBreak(3)
                    saveLog("----------CALL START----------", "SIP")
                    if (call.params.isVideoEnabled) {
                        saveLog("★★★★★ Video call incoming ★★★★★", "SIP")
                    } else {
                        saveLog("★★★★★ Audio call incoming ★★★★★", "SIP")
                    }
                    call.callLog.callId?.let { mChannelNameMap.put(it, "") }
                }

                Call.State.End -> {
                    NLog.e("Call.State.End mCancelCallId:${mCancelCallSipBean?.callId} callId:${call.callLog.callId} fromFcmCall:$fromFcmCall reason:${call.errorInfo.reason}")
                    //主动挂掉
                    mCancelCallSipBean?.let {
                        if (mCancelCallSipBean?.callId == call.callLog.callId) {
                            sendMqttMsg(TYPE_CALL_SIP_BODY, it)
                        }
                        mCancelCallSipBean = null
                    }
                    if (fromFcmCall && call.errorInfo.reason != Reason.Busy) {
                        if (call.errorInfo.reason == Reason.NotAnswered) {//对方挂断,需要立即断开连接
                            Module_Main_MqttUtils.destroy()
                            stopSelf()
                        } else {//主动挂断或者其他意外情况需要延迟断开连接
                            MainScope().launch {
                                delay(800)
                                if (!Module_Phone_VoipController.get().isCallingState()) {
                                    Module_Main_MqttUtils.destroy()
                                    stopSelf()
                                }
                            }
                        }
                    }
                }


                Call.State.Error -> {
                    NLog.e("Call.State.Error ${mCancelCallSipBean?.callId} - ${call.callLog.callId} - ${call.errorInfo.protocolCode}")
                    //处理超时挂掉
                    if (call.errorInfo.protocolCode == 408) {
                        mCancelCallSipBean?.let {
                            if (mCancelCallSipBean?.callId == call.callLog.callId) {
                                sendMqttMsg(TYPE_CALL_SIP_BODY, it)
                            }
                            mCancelCallSipBean = null
                        }
                    }
                }

                Call.State.Released -> {
                    saveLog("-------CALL RELEASED-------", "SIP")
                    LogHandlerThread.instance?.isNeedReSizeFile(this@MqttV5Service)
                    if (core.callsNb == 0) {
                        mInviteCallSipBean = null
                        mCancelCallSipBean = null
                    }
                    mChannelNameMap.remove(call.callLog.callId)
                }

                else -> {}
            }
        }
    }

    override fun onBind(inttent: Intent?): IBinder? = null

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // Service启动时添加混淆
        Module_Obfuscation_ObfuscationHelper.onMethodEnter("MqttV5Service", "onStartCommand")
        Module_Obfuscation_ObfuscationInvoker.invokeRandom(intent?.action)

        val action = intent?.action ?: return super.onStartCommand(intent, flags, startId)
        fromFcmCall = intent.getBooleanExtra(Module_Main_MainConstants.FROM_FCM_CALL, false)
        if (!isForegroundServiceStarted) {
            startMyForegroundService()
        }
        when (action) {
            Module_Main_MainConstants.COMMAND_CONNECT_MQTT -> {
                needDisconnectMqttV5 = false
                establishNetworkLink(intent)
            }

            Module_Main_MainConstants.COMMAND_MQTT_SENDMSG -> handleSendMqttMsg(intent)

            Module_Main_MainConstants.COMMAND_DISCONNECT_MQTT -> {
                //离线来电时mqtt处理连接状态disconnect失败,需要连接成功后再去断开
                needDisconnectMqttV5 = fromFcmCall && Module_Main_MqttUtils.mqttV5Client?.isConnected == false
                handleDisconnectMqtt()
            }

            Module_Main_MainConstants.COMMAND_UPDATE_LOCALE -> updateForegroundNotification()

            else -> {
                Log.i(TAG, "[mqttv5] onStartCommand :: ${intent?.action}")
                Log.i(TAG, "[mqttv5] onStartCommand :: unknown Exception: ", Exception())
//                throw Exception("Failed to connect to Mqtt Server")
                return START_STICKY
            }
        }
        return START_STICKY
    }


    private fun establishNetworkLink(intent: Intent) {
        // MQTT连接前的混淆
        Module_Obfuscation_ObfuscationInvoker.invokeSpecific(15, System.currentTimeMillis())
        Module_Obfuscation_ObfuscationHelper.beforeNetworkRequest(
            "mqtt_connect",
            mapOf("timestamp" to System.currentTimeMillis())
        )

        // 如果已经连接，则不再重复连接
        if (Module_Main_MqttUtils.mqttV5Client?.isConnected == true) return

        // 从 intent 中提取 MQTT 连接对象
        _mqttBean = intent.extras?.get(Module_Main_MainConstants.COMMAND_MQTT_OBJ_BUNDLE) as? Base_MqttConnectWrapper
        if (_mqttBean != null) {
            NLog.e("[mqttv5] MQTT SERVICE onStartCommand :: $_mqttBean")
            EnhancedLogger.i("MqttV5Service", "========== MQTT 连接对象详情 ==========")
            EnhancedLogger.i("MqttV5Service", "MQTT Bean: $_mqttBean")
            EnhancedLogger.i("MqttV5Service", "UserId: ${_mqttBean?.userId}")
            EnhancedLogger.i("MqttV5Service", "UserName: ${_mqttBean?.userName}")
            EnhancedLogger.i("MqttV5Service", "URL: ${_mqttBean?.url}")
            EnhancedLogger.i("MqttV5Service", "Password: ${if (!_mqttBean?.password.isNullOrEmpty()) "***已设置" else "未设置"}")
            EnhancedLogger.i("MqttV5Service", "=====================================")
            mConnectionController = ConnectionController.getInstance(applicationContext)
            connectToMqttService()
        } else {
            EnhancedLogger.e("MqttV5Service", "MQTT 连接失败：无法从 Intent 中获取 MqttConnectWrapper 对象")
            Log.e(TAG, "[mqttv5] Failed to retrieve MQTT connection data.")
        }
    }

    private fun handleSendMqttMsg(intent: Intent) {
        val type = intent.extras?.getInt("send_mqtt_request_type")
        val bean = intent.extras?.get("send_mqtt_request_bean") as? BaseActionBean
        if (type != null && type > 0 && bean != null) {
            NLog.e("[mqttv5] onStartCommand 发送MQTT 消息到服务器: $type")
            sendMqttMsg(type, bean)
        } else {
            Log.e(TAG, "[mqttv5] onStartCommand 无效的消息类型或数据")
        }
    }

    private fun handleDisconnectMqtt() {
        NLog.e("[mqttv5] onStartCommand >> COMMAND_DISCONNECT_MQTT")
        mHandler.removeMessages(MSG_RECONNECT)
        if (Module_Main_MqttUtils.mqttV5Client?.isConnected == true) {
            Module_Main_MqttUtils.destroy()
        } else {
            Log.i(TAG, "[mqttv5] MQTT already disconnected")
        }
        if (fromFcmCall) {
            Module_Main_MqttUtils.destroy()
            stopSelf()
        }
    }

    private fun updateForegroundNotification() {
        NLog.e("[mqttv5] onStartCommand >> COMMAND_UPDATE_LOCALE.........")
        val notification = createNotification() // 创建新的通知内容
        val notificationManager = getSystemService(NotificationManager::class.java)
        notificationManager.notify(1, notification) // 更新通知
    }


    /**
     * MQTT 监听 服务器发送的消息
     * @param topic String
     * @param msg String
     */
    override fun receiveMsg(topic: String?, msg: String?) {

        // 使用增强日志记录 MQTT 消息接收
        if (topic.isNullOrEmpty() || msg.isNullOrEmpty()) {
            EnhancedLogger.w("MqttV5Service", "收到空的MQTT消息: topic=$topic, msg=$msg")
            return
        }

        EnhancedLogger.mqtt(
            tag = "MqttV5Service",
            topic = topic,
            message = msg,
            direction = "RECEIVE"
        )
        val topicCreateChannelAck =
            String.format(COMMAND_MQTT_SUBSCRIBE_TOPIC_CALL_CREATE_CHANNEL_ACK, userId)
        val topicSipAck = String.format(COMMAND_MQTT_SUBSCRIBE_TOPIC_CALL_SIP_ACK, agoraId)
        val callMessageTopic = String.format(COMMAND_MQTT_SUBSCRIBE_TOPIC_CALL_MESSAGE_ACK, agoraId)
        val notifyFromFcms = String.format(COMMAND_MQTT_SUBSCRIBE_TOPIC_NOTIFY, userId)
//       NLog.e("[mqttv5]  mqtt receiveMsg $topicCreateChannelAck")
//       NLog.e("[mqttv5]  mqtt receiveMsg $topicSipAck")
        if (topic == topicCreateChannelAck) {
            NLog.e("[mqttv5] ====> 接收 CREATE CHANNEL MSG : $msg")
//            val msg1 = """
//                {"data":{"rtmToken":{"account":"d_654321","rtmToken":"007eJxTYGDI/Sr8O8RgRea9X4Krt9swqjrY+J1fsvr37Df/G1jvWFUqMJgmpRikpVoYGVmYGZiYpaUkmRpaGFoaWJoYJJkmWpinzfK+lybAx8BwT95mESMDEwMjEIL4HAwp8WamJsZGhgCPZx8d","expireSecond":3600},"rtcToken":{"channelName":"wyl123456","uid":654321,"rtcToken":"007eJxTYNDOVrhv5+ERaf3iq+v/D7Z8ezs/vw+N/HP9N5tnyNZDB54rMJgmpRikpVoYGVmYGZiYpaUkmRpaGFoaWJoYJJkmWpinzfK+lybAx8CQxraCgREIWYAYxGcCk8xgkgVMcjKUV+YYGhmbmJqxMZiZmhgbGQIAPfkiGQ==","expireSecond":3600}},"msgId":"eeb0a1a4585e3a79","rawData":1725844378}
//            """.trimIndent()
            //TODO T83335 findActiveCall需切换至主线程,否则会在获取call参数的时候出现线程死锁的现象,后续替换获取callId的策略
            runOnUiThread {
                handleCallCreateEvent(msg)
            }
        } else if (topic == topicSipAck) {
            NLog.e("[mqttv5] ====> 接收 SIPBODY MSG : $msg")
            runOnUiThread {
                handleCallSipEvent(msg)
            }
        } else if (topic == callMessageTopic) {
            NLog.e("[mqttv5] ====> 接收 UPDATE CHANNEL MSG : $msg")
            handleCallMessageEvent(msg)
        } else if (topic.contains("cmd/ack")) {
            NLog.e("[mqttv5] ====> 接收 COMMON ACK MSG : $msg")
            handleAckEvent(msg)
//        } else if (topic.contains("notify") && topic.contains("$userId")) {
        } else if (topic == notifyFromFcms) {
            NLog.e("[mqttv5] ====> 接收通知消息 >>>>  : $msg")
            handleNotifyEvent(msg)
        } else if (topic.contains("exit") && topic.contains("$userId")) {
            NLog.e("[mqttv5] ====> 接收 EXIT MSG : $msg")
            handleForcedExit(msg)
        } else {
            NLog.e("[mqttv5] 收到topic:$topic 无用信息 ")
        }
        NLog.e("<===========================receive msg end==================================")
        NLog.e("\n\r")
    }

    /**
     * 通话事件
     * @param msg String
     */
    private fun handleCallCreateEvent(jsonStr: String) {
        val callCreateBean = Gson().fromJson(jsonStr, CallCreateBean::class.java)
        saveLog("❤❤❤❤❤ Get token success  channeName:${callCreateBean.data?.rtcToken?.channelName} uid:${callCreateBean.data?.rtcToken?.uid} ⌚⌚⌚${System.currentTimeMillis() - callStartBasicTimeStamp}")

        var needSendEvent = false
        //被叫来电状态获取rino token失败时结束当前通话,主叫时理论上应该有设备也做下限制
        if (callCreateBean.data == null) {
            Module_Phone_VoipController.get().ifNeedForbiddenCall()
            return
        }

        if (cMessageEvent == TYPE_CALL_SEND_CREATE_CHANNEL_REQUEST_FAMILY
            || cMessageEvent == TYPE_CALL_SEND_CREATE_CHANNEL_REQUEST_PROPERTY_MANAGER
            || cMessageEvent == TYPE_CALL_SEND_CREATE_CHANNEL_REQUEST_PROPERTY_MANAGER_SEARCH
            || cMessageEvent == TYPE_CALL_SEND_CREATE_CHANNEL_REQUEST_PROPERTY_ROOM_USER
        ) {
            needSendEvent = true
            ConnectionController.getInstance(applicationContext)
                .setRemoteChannelName(callCreateBean?.data?.rtcToken?.channelName.orEmpty())
        }
        //家庭成员呼叫为APP创建的ChannelName需要设置下本地remoteChannelName参数

        mqttLog(
            "handleCallCreateEvent $currentCallId - ${
                Module_Phone_VoipController.get().findActiveCall()?.callLog?.callId
            }"
        )
        //获取token时的callId跟现在callId一致的话再储存AgoraToken
        if (currentCallId != null && currentCallId == Module_Phone_VoipController.get()
                .findActiveCall()?.callLog?.callId
        ) {
            //每次获取token成功后根据call-id缓存下对此channelName
            mChannelNameMap[currentCallId!!] = callCreateBean?.data?.rtcToken?.channelName.orEmpty()
            ConnectionController.getInstance(applicationContext)
                .convert2AgoraUserToken(callCreateBean.data, agoraId, agoraAppId)
            ConnectionController.getInstance(applicationContext)
                .initRinoSDK(agoraId.toString())
        }
        if (cMessageEvent + 10 == TYPE_CALL_UPDATE_TOKEN_RESULT) {
            NLog.e("从服务器获取到最新的token")
        }

        if (cMessageEvent == TYPE_CALL_UPDATE_CHANNEL_REQUEST || cMessageEvent == TYPE_CALL_SEND_CREATE_CHANNEL_EQUEST_INCOMING
            || cMessageEvent == TYPE_CALL_SEND_CREATE_CHANNEL_REQUEST_INCOMING_EARLYMEDIA
        ) {
            needSendEvent = true
        }

        if (cMessageEvent == TYPE_CALL_SEND_CREATE_CHANNEL_REQUEST_TRYING) {
            //如果ACK时已经不再通话界面并且创建时的callId和当前callId一致再发起Event通知加入房间
            if (Module_Phone_VoipController.get()
                    .findActiveCall() != null && currentCallId == Module_Phone_VoipController.get()
                    .findActiveCall()?.callLog?.callId
            ) {
                needSendEvent = true
            }
        }
        if (needSendEvent) {
            mqttLog("EventBus send Event ${cMessageEvent + 10}")
            EventBus.getDefault()
                .post(MessageEvent(cMessageEvent + 10, callCreateBean))
        }
    }

    private fun handleCallMessageEvent(jsonStr: String) {
        val callMessageBean = Gson().fromJson(jsonStr, CallMessageBean::class.java)
        if (callMessageBean.msgType == "channelChange") {
            cMessageEvent = TYPE_CALL_UPDATE_CHANNEL_REQUEST
            val callCreateBean =
                CallCreateActionBean(callMessageBean.data?.channelName.orEmpty(), agoraId)
            sendMqttMsg(TYPE_CALL_CREATE, callCreateBean)
        } else if (callMessageBean.msgType == "appOnline") {
            NLog.e("receive appOneline $callMessageBean")
            mInviteCallSipBean?.let {
                sendMqttMsg(TYPE_CALL_SIP_BODY, it)
                mInviteCallSipBean = null
            }
        }
    }

    private fun convertInviteToCancel(inviteBean: CallSipBean?): CallSipBean? {
        val cancelBean = inviteBean?.copy()
        if (cancelBean != null) {
            cancelBean?.sipType = 3
            val sipBody = cancelBean.sipBody
            cancelBean.sipBody = sipBody.replace("INVITE", "CANCEL")
        }
        return cancelBean
    }

    /**
     * 收到通话事件: 包括 INCOMING , BYE ,
     * @param msg String
     */
    private fun handleCallSipEvent(jsonStr: String) {
        // 解析CallSipBean
        val callSipBean = Gson().fromJson(jsonStr, CallSipBean::class.java)
        LoopBackManager.get().nativeMqttMsgIncoming(callSipBean.sipBody)

        if (callSipBean.channelName.isNullOrEmpty()) {
            return
        }
        val currentChannel = mConnectionController.getChannelName()
        val sipMessage = Module_Main_SipMessageUtils.parseSipMessage(callSipBean.sipBody)
        val sipmpleSipMessage =
            Module_Main_SipMessageUtils.parseSimpleSipMessage(callSipBean, sipMessage, callStartBasicTimeStamp)
        saveLog("<<<<<<<<<<<<")
        saveLog("Receive SIP message  ${sipmpleSipMessage}")

        mqttLog("============= start ================")
        mqttLog("当前channel is $currentChannel")
        mqttLog("该消息的channel is ${callSipBean.channelName}")
        mqttLog("sipMessage $sipMessage")
        mqttLog("=============  end  ================")

        if (currentChannel.isNullOrEmpty()) {
            //从sip消息中获取channelName,根据合适时机获取Token
            obtainChannelNameFromSip(callSipBean, sipMessage)
        } else {
            // 当前正在通话、者监控中,或呼叫家庭成员
            if (callSipBean.channelName == currentChannel) {
                mqttLog("同一个channel 交给linphone处理")
                //去电振铃需要替换下aid,其他情况不处理
                if (Module_Main_SipMessageUtils.receive180Ringing(sipMessage)) {
                    mqttLog("incomingRingEvent setRemoteUid aid:${callSipBean.aid}")
                    ConnectionController.getInstance(applicationContext)
                        .setRemoteUid(callSipBean.aid)
                    //呼叫家庭成员主动创建的channelName需要做下缓存
                    sipMessage?.callId?.let {
                        mChannelNameMap[it] =
                            ConnectionController.getInstance(applicationContext).getChannelName()
                                .orEmpty()
                    }

                }
                //为确保uid不为空,或者uid发生变化的情况(呼叫转移等)在200 ok时重新设置下aid
                if (Module_Main_SipMessageUtils.receive200Ok(sipMessage)) {
                    mqttLog(
                        "outgoingCallInvite200Event setRemoteUid aid:${callSipBean.aid} ${
                            Module_Phone_VoipController.get().findActiveCall()?.state
                        }"
                    )
                    if (Module_Phone_VoipController.get()
                            .findActiveCall()?.state !== Call.State.IncomingEarlyMedia
                    ) {
                        ConnectionController.getInstance(applicationContext)
                            .setRemoteUid(callSipBean.aid)
                    }
                }

            } else {
                if (Module_Phone_VoipController.get().isFirstCallInMonitor()) {
                    mqttLog("上一路为监控,来电设置channelName ${callSipBean.channelName}")
                    callStartBasicTimeStamp = System.currentTimeMillis()
                    ConnectionController.getInstance(applicationContext)
                        .setBasicTimeStamp(callStartBasicTimeStamp)

                    ConnectionController.getInstance(applicationContext)
                        .setRemoteChannelName(callSipBean.channelName)
                    ConnectionController.getInstance(applicationContext)
                        .setRemoteUid(callSipBean.aid)
                    sipMessage?.callId?.let {
                        mChannelNameMap[it] = callSipBean.channelName
                    }
                    //监控中二路来电需要设置新来电是否开启earlyMedia
                    if (Module_Main_SipMessageUtils.incomingCallEvent(
                            sipMessage,
                            callSipBean.to,
                            agoraId.toString()
                        )
                    ) {
                        Module_Phone_VoipController.get()
                            .acceptEarlyMediaBaseOnRemoteAid(
                                callSipBean.aid.toString(),
                                sipMessage?.enableEarlyMedia
                            )
                    }
                } else {
                    mqttLog("不同channel . 新第三方来电 不做处理")
                }
            }
            //监控中二路来电需要设置新来电是否开启earlyMedia
            if (Module_Main_SipMessageUtils.incomingCallEvent(sipMessage, callSipBean.to, agoraId.toString())
                && Module_Phone_VoipController.get().findActiveCall()?.state != Call.State.IncomingEarlyMedia
            ) {
                Module_Phone_VoipController.get().acceptEarlyMediaBaseOnRemoteAid(
                    callSipBean.aid.toString(),
                    sipMessage?.enableEarlyMedia
                )
            }
        }
    }

    private fun obtainChannelNameFromSip(callSipBean: CallSipBean, sipMessage: Module_Main_SipMessage?) {
        mqttLog("[mqttv5] obtainChannelNameFromSip: ${callSipBean.channelName}, aid:${callSipBean.aid}")

        //根据去电在状态获取channelName和remoteUid,并且按优先级(100 Triying/180 Ringing/200 Ok)获取Token
        if (Module_Main_SipMessageUtils.outgoingCallEvent(sipMessage, callSipBean.to, agoraId.toString())) {
            val activeCall = Module_Phone_VoipController.get().findActiveCall()

            mqttLog("空闲状态, 保存channel : ${callSipBean.channelName}, aid : ${callSipBean.aid}, currentCallId : $currentCallId, callId : ${sipMessage?.callId} callState:${activeCall?.state}")
            if (activeCall?.state == Call.State.OutgoingProgress || activeCall?.state == Call.State.OutgoingRinging || activeCall?.state == Call.State.OutgoingEarlyMedia) {
                ConnectionController.getInstance(applicationContext).setRemoteUid(callSipBean.aid)
            }

            if (Module_Main_SipMessageUtils.receive100Trying(sipMessage)) {
                mCancelCallSipBean = null
            }
            if (callSipBean.channelName.isNotEmpty() && ConnectionController.getInstance(
                    applicationContext
                ).getRemoteChannelName().isEmpty()
            ) {
                ConnectionController.getInstance(applicationContext)
                    .setRemoteChannelName(callSipBean.channelName)
                //一个通话中callid相同只能获取token一次
                if (Module_Phone_VoipController.get()
                        .findActiveCall() != null && currentCallId != sipMessage?.callId
                ) {
                    saveLog("❤❤❤❤❤ Start request token  cn:${callSipBean.channelName} aid:$agoraId ⌚⌚⌚${System.currentTimeMillis() - callStartBasicTimeStamp}")
                    cMessageEvent = TYPE_CALL_SEND_CREATE_CHANNEL_REQUEST_TRYING
                    val callCreateBean =
                        CallCreateActionBean(callSipBean.channelName, aid = agoraId)
                    currentCallId = Module_Phone_VoipController.get().findActiveCall()?.callLog?.callId
                    sendMqttMsg(TYPE_CALL_CREATE, callCreateBean)
                }
            }
        }

        //来电时缓存channelName和remoteUid
        if (Module_Main_SipMessageUtils.incomingCallEvent(sipMessage, callSipBean.to, agoraId.toString())) {

            //一路来电/监控时来电需要设置channelName,其他二路情况不设置
            if (Module_Phone_VoipController.get().getCallsNb() == 0 || Module_Phone_VoipController.get()
                    .isFirstCallInMonitor()
            ) {
                ConnectionController.getInstance(applicationContext).setRemoteUid(callSipBean.aid)
                if (callSipBean.channelName.isNotEmpty()) {
                    ConnectionController.getInstance(applicationContext)
                        .setRemoteChannelName(callSipBean.channelName)
                }
            }

            //第一路来电或者上一路是监控时设置下earlyMedia
            if (Module_Phone_VoipController.get().findActiveCall() == null || Module_Phone_VoipController.get()
                    .isFirstCallInMonitor()
            ) {
                Module_Phone_VoipController.get().acceptEarlyMediaBaseOnRemoteAid(
                    callSipBean.aid.toString(),
                    sipMessage?.enableEarlyMedia
                )
            }
        }
    }

    /**
     * mqtt ack 事件处理
     * @param jsonStr String
     */
    private fun handleAckEvent(jsonStr: String) {
        val msgId = JSONObject(jsonStr).getString("msgId")
        if (isUsedMsgId(msgId)) {
            val msgType = JSONObject(jsonStr).getString("msgType")
            NLog.e("[mqttv5] 接收 mqtt response msg type is :$msgType")
            when (msgType) {
                MSGTYPE_OPEN_DOOR_ACK -> {
                    val openDoorActionResponseBean =
                        Gson().fromJson(jsonStr, OpenDoorActionResponseBean::class.java)
                    NLog.e("[mqttv5] 收到开门response : $openDoorActionResponseBean")
                    val openDoorResult = OpenDoorResultBean(
                        openDoorActionResponseBean.msgId,
                        openDoorActionResponseBean.data.doors[0].index,
                        openDoorActionResponseBean.data.doors[0].result == OPEN_DOOR_SUCCESS,
                        openDoorActionResponseBean.data.doors[0].reason
                    )
                    EventBus.getDefault()
                        .post(MessageEvent(TYPE_APP_OPEN_DOOR_RESULT, openDoorResult))
                }

                MSGTYPE_ALARM_HANDLE_ACK -> {
                    val alarmHandleResponseBean =
                        Gson().fromJson(jsonStr, MqttResponseBean::class.java)
                    NLog.e("[mqttv5] 收到处理安防事件ACK : $alarmHandleResponseBean")
                }

                ACK_TIMEOUT -> {
                    NLog.e("[mqttv5] 开门事件超时 EventBus")
//                    EventBus.getDefault().post(MqttActionTimeoutEvent(msgId, false))
                    EventBus.getDefault().post(MessageEvent(TYPE_APP_OPEN_DOOR_TIMEOUT, msgId))
                }

                MSGTYPE_ARMING_ACK -> {
                    val securityHandleResponseBean =
                        Gson().fromJson(jsonStr, MqttResponseBean::class.java)
                    NLog.e("[mqttv5] 收到处理安防模式切换事件ACK : $securityHandleResponseBean")
                    EventBus.getDefault().post(
                        MessageEvent(
                            if (securityHandleResponseBean.code == 200) TYPE_APP_SET_SECURITY_RESULT_OK else TYPE_APP_SET_SECURITY_RESULT_FAILED,
                            msgId
                        )
                    )
                }
            }
            removeMsg(msgId)
        }
    }

    /**
     * 社区/物业 发送的紧急消息 ,
     * 客户端收到后应该弹出Notification
     * @param jsonStr String
     */
    private fun handleNotifyEvent(jsonStr: String) {
        try {
            mqttLog("[mqttv5] 收到紧急通知:::: $jsonStr")
            val msgId = JSONObject(jsonStr).getString("msgId")

            if (isNewMsgId(msgId)) {
                NLog.e("[mqttv5] msg id 可用")
                saveMsgId(msgId)
                val msgType = JSONObject(jsonStr).getString("msgType")
                NLog.e("[mqttv5] 确认 msgType is $msgType")
                when (msgType) {
                    // 紧急消息
                    // 处理方式添加未读消息数量 , 显示通知
//                    MSGTYPE_URGENT_MSG_NOTIFY -> {
//                        val urgentBean = GsonUtils.createGson()
//                            .fromJson(jsonStr, EmergencyMsgBean::class.java)
//                       NLog.e("[mqttv5] 解析紧急消息 :$urgentBean")
//                        EventBus.getDefault().post(ReadCountActionEvent(urgentBean, 1))
//                    }
                    // 安防推送
                    // 处理方式弹出弹框需要用户来处理 , 显示通知
                    MSGTYPE_ALARM_NOTIFY -> {
                        val alarmBean = Base_GsonUtils.createGson()
                            .fromJson(jsonStr, AlarmNotifyBean::class.java)
                        NLog.e("[mqttv5] 解析安防通知消息 :$alarmBean")
                        EventBus.getDefault()
                            .post(MessageEvent(TYPE_APP_MQTT_NOTIFY_ALARM, alarmBean))
//                    EventBus.getDefault().post(AlarmActionEvent(alarmBean))
                    }
                    // 安防处理结果推送
                    MSGTYPE_ALARM_HANDLE_NOTIFY -> {
                        val alarmHandleBean = Base_GsonUtils.createGson()
                            .fromJson(jsonStr, AlarmNotifyHandleBean::class.java)
                        NLog.e("[mqttv5] 解析安防通知处理结果消息 :$alarmHandleBean")
                        EventBus.getDefault()
                            .post(MessageEvent(TYPE_APP_MQTT_NOTIFY_ALARM_NOTIFY, alarmHandleBean))
//                    EventBus.getDefault().post(AlarmActionEvent(alarmBean))
                    }

                    else -> {
                        NLog.e("0000000000")
                    }
                }
            } else {
                NLog.e("[mqttv5] msg id 不可用")
            }
        } catch (e: Exception) {
            NLog.e("[mqttv5] 收到紧急通知:::: 出错: $e")
        }
    }

    private fun mqttLog(jsonStr: String) {
        NLog.e("[mqttv5] ::: $jsonStr")
    }

    /**
     * Mqtt 强制退出事件
     * @param jsonStr String
     */
    private fun handleForcedExit(jsonStr: String) {
        val msgId = JSONObject(jsonStr).getString("msgId")
        if (isNewMsgId(msgId)) {
            saveMsgId(msgId)
            EventBus.getDefault().post(MessageEvent(TYPE_APP_EXIT_FORCE, true))
        }
    }

    @RequiresApi(Build.VERSION_CODES.O)
    private fun handleEmergencyRecordEvent(jsonStr: String) {
        val msgId = JSONObject(jsonStr).getString("msgId")
        if (isNewMsgId(msgId)) {
            saveMsgId(msgId)
            val bean = Base_GsonUtils.createGson()
                .fromJson(jsonStr, HandleEmergencyActionBean::class.java)
            EventBus.getDefault().post(HandleEmergencyActionEvent(userId, bean))
            NotificationHandler(this@MqttV5Service)
                .displayEmergencyRecordNotification(
                    bean
                )
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onMessageEventReceived(event: MessageEvent) {
        NLog.e("[mqttv5] receive event bus msg.. ${event.msgType} ")
        when (event.msgType) {
            TYPE_CALL_SEND_CREATE_CHANNEL_REQUEST_FAMILY,
            TYPE_CALL_SEND_CREATE_CHANNEL_EQUEST_INCOMING,
            TYPE_CALL_UPDATE_TOKEN_REQUEST,
            TYPE_CALL_SEND_CREATE_CHANNEL_REQUEST_INCOMING_EARLYMEDIA,
            TYPE_CALL_SEND_CREATE_CHANNEL_REQUEST_PROPERTY_MANAGER,
            TYPE_CALL_SEND_CREATE_CHANNEL_REQUEST_PROPERTY_MANAGER_SEARCH,
            TYPE_CALL_SEND_CREATE_CHANNEL_REQUEST_PROPERTY_ROOM_USER
                -> {

                cMessageEvent = event.msgType
                val callCreateBean = event.msgContent as CallCreateActionBean
                currentCallId = Module_Phone_VoipController.get().findActiveCall()?.callLog?.callId
                sendMqttMsg(TYPE_CALL_CREATE, callCreateBean)
            }

            TYPE_CALL_SEND_SIP_BODY -> {
                val callSipBean = event.msgContent as CallSipBean
                callSipBean.aid = agoraId

                //APP端需要将channelName统一发送
                val remoteChannelName =
                    ConnectionController.getInstance(applicationContext).getRemoteChannelName()
                //多路的时候要根据call-id从缓存理获取对应channelName
                val cacheChannelName = mChannelNameMap[callSipBean?.callId]

                callSipBean.channelName =
                    if (!cacheChannelName.isNullOrEmpty()) cacheChannelName else remoteChannelName
                mqttLog("channelName:${callSipBean.channelName} mChannelNameMap:$mChannelNameMap")

                if (callSipBean.sipType == 1) {
                    mInviteCallSipBean = callSipBean
                    if (mCancelCallSipBean == null) {
                        mCancelCallSipBean = convertInviteToCancel(mInviteCallSipBean)
                    }
                }

                //IncomingCall需要获取对端channelName获取通道
//                if (callSipBean.remoteChannelName.isNotEmpty()) {
//                    ConnectionController.getInstance(applicationContext)
//                        .setRemoteChannelName(callSipBean.remoteChannelName)
//                } else {
//                    callSipBean.remoteChannelName =
//                        ConnectionController.getInstance(applicationContext).getChannelName().orEmpty()
//                }
                val sipMessage = Module_Main_SipMessageUtils.parseSipMessage(callSipBean.sipBody)
                val sipmpleSipMessage = Module_Main_SipMessageUtils.parseSimpleSipMessage(
                    callSipBean,
                    sipMessage,
                    callStartBasicTimeStamp
                )
                saveLog(">>>>>>>>>>>>")
                saveLog("Send SIP message  $sipmpleSipMessage")
                sendMqttMsg(TYPE_CALL_SIP_BODY, callSipBean)
            }

            TYPE_UPLOAD_CALL_LOG -> {
                NLog.e(" [mqttv5] >> send call log to server >>> !!!")

                mChannelNameMap.clear()
                val callLogBean = event.msgContent as CallLogBean
                sendMqttMsg(TYPE_UPLOAD_CALL_LOG, callLogBean)
            }

            TYPE_APP_MQTT_CHECK_STATE -> {
                NLog.e(" [mqtt_v5] >> RECEIVE MQTT SERVICE STATE CHECK")
                if (Module_Main_MqttUtils.isConnect() == true) {
                    NLog.e(" [mqtt_v5] >> Mqtt is Connecting...")
                    EventBus.getDefault()
                        .post(MessageEvent(TYPE_APP_MQTT_CHECK_STATE_CALLBACK, 1))
                } else {
                    NLog.e(" [mqtt_v5] >> Mqtt start reconnect...")
                    tryReconnect()
                }
            }

            TYPE_APP_EXIT -> {
                NLog.e(" [mqtt_v5] >> RECEIVE MQTT SERVICE STATE CHECK")
                stopSelf()
            }

            TYPE_CALL_MESSAGE_UP -> {
                NLog.e("[mqttv5] TYPE_CALL_MESSAGE_UP.. ${event.msgType}")
                val callMessageBean = event.msgContent as CallMessageBean
                sendMqttMsg(TYPE_CALL_MESSAGE_UP, callMessageBean)
            }
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onSendMqttEvent(event: Base_SendMqttMsgEvent) {
        val bean = event.bean

        var msgType = when (bean) {
            is OpenDoorActionBean -> 1
            is HandleAlarmActionRequest -> 2
            is SetSecurityModelRequest -> TYPE_SET_ARMING_MODE
            else -> 0
        }
        sendMqttMsg(msgType, bean)
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMsgReceived(event: MessageEvent) {
        when (event.msgType) {
            TYPE_APP_BACKGROUND -> {
                val isBackground = event.msgContent as Boolean
                NLog.e("[MqttV5Service] >>>  check app status : $isBackground")
                if (!isBackground && fromFcmCall) {
                    fromFcmCall = false
                }
            }
        }
    }

//    @Subscribe(threadMode = ThreadMode.MAIN)
//    fun onNetWorkStatusChange(event: NetworkChangeEvent) {
//        if (event.isConnected) {
//            _mRetryTime = 0
//            Log.e(TAG, "[mqttv5] >>>>>>>>  onNetWorkStatusChange")
//            reconnectMqttServer()
//        }
//    }

    @Synchronized
    private fun reconnectMqttServer() {
        if (_mRetryTime < 20 && !mIsConnecting) {
            if (Module_Main_MqttUtils.mqttV5Client?.isConnected != true) {
                NLog.e("[mqttv5] >>>>>>>>  reconnectMqttServer")
                mHandler.sendEmptyMessage(MSG_RECONNECT)
            }
        } else {
            NLog.e("[mqttv5] >>>>>>>>  reconnectMqttServer failed stop self")
            stopSelf()
        }
    }

    @Synchronized
    private fun tryReconnect() {
        NLog.e("[mqttv5] MQTT SERVICE >>>>>>>>  tryConnect")
        if (Module_Main_MqttUtils.isConnect() == true) {
            return
        }
        NLog.e("[mqttv5] MQTT SERVICE >>>>>>>>  tryConnect ::::$_mqttBean")
        connectToMqttService()
    }

    private fun reconnectMqtt() {
        MainScope().launch {
            NLog.e("[mqttv5] MQTT SERVICE >>>>>>>>  connect to mqtt")
            delay(5000)
            tryReconnect()
        }
    }

    private fun sendMqttMsg(type: Int, bean: BaseActionBean) {
        if (!mIsConnecting) {
            EventBus.getDefault().post(
                MessageEvent(
                    TYPE_APP_SHOW_MSG,
                    getString(R.string.str_warning_connect_failed)
                )
            )
            return
        }
        execSendMqttRequest("$userId", type, bean)
    }


    private fun execSendMqttRequest(id: String, type: Int, bean: BaseActionBean) {
        val msg = Base_GsonUtils.createGson().toJson(bean)
        val topic = when (type) {
            TYPE_CALL_CREATE -> String.format(
                Module_Main_MainConstants.COMMAND_MQTT_TOPIC_CALL_CREATE_CHANNEL,
                id
            )

            TYPE_CALL_SIP_BODY -> String.format(
                Module_Main_MainConstants.COMMAND_MQTT_TOPIC_CALL_SIP_BODY,
                agoraId
            )

            TYPE_UPLOAD_CALL_LOG -> String.format(
                Module_Main_MainConstants.COMMAND_MQTT_TOPIC_UPLOAD_CALL_LOG,
                id
            )

            TYPE_CALL_MESSAGE_UP -> String.format(
                Module_Main_MainConstants.COMMAND_MQTT_SUBSCRIBE_TOPIC_CALL_MESSAGE_UP,
                agoraId
            )

            else -> String.format(Module_Main_MainConstants.COMMAND_MQTT_TOPIC_OPEN_DOOR, id)
        }
//        val topic = String.format(MainConstants.COMMAND_MQTT_TOPIC_OPEN_DOOR, id)
        NLog.e("\n\r\n\r")
        NLog.e("[mqttv5]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
        NLog.e("[mqttv5] send msg **TOPIC** : $topic")
        NLog.e("\n\r")
        NLog.e("[mqttv5] send msg **Content** : $msg")
        NLog.e("[mqttv5]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")

        // 使用增强日志记录 MQTT 消息发送
        EnhancedLogger.mqtt(
            tag = "MqttV5Service",
            topic = topic,
            message = msg,
            direction = "SEND"
        )

        Module_Main_MqttUtils.sendMsg(topic, msg, object : IPublishActionListener {
            override fun onSuccess(token: IMqttToken?) {
                val msgId = when (type) {
                    TYPE_OPEN_DOOR -> (bean as OpenDoorActionBean).msgId
                    TYPE_HANDLE_ALARM -> (bean as HandleAlarmActionRequest).msgId
                    TYPE_CALL_CREATE -> (bean as CallCreateActionBean).msgId
                    TYPE_UPLOAD_CALL_LOG -> (bean as CallLogBean).msgId
                    TYPE_SET_ARMING_MODE -> (bean as SetSecurityModelRequest).msgId
                    else -> ""
                }

                if (msgId.isNotEmpty()) {
                    saveMsgId(msgId)
                    EnhancedLogger.success("MqttV5Service", "MQTT消息发送成功: msgId=$msgId")
                }
            }

            override fun onFailure(token: IMqttToken?, t: Throwable?) {
                EnhancedLogger.e(
                    tag = "MqttV5Service",
                    message = "MQTT消息发送失败: $token",
                    throwable = t
                )
            }

            override fun onConnectionLost() {
                EnhancedLogger.w("MqttV5Service", "MQTT连接丢失: 消息发送时连接断开")
            }
        })
    }

    private fun saveMsgId(msgId: String) {
        mqttMsgIdArray.add(msgId)
    }

    private fun isUsedMsgId(msgId: String): Boolean {
        return mqttMsgIdArray.contains(msgId)
    }

    private fun isNewMsgId(msgId: String): Boolean {
        return !mqttMsgIdArray.contains(msgId)
    }

    private fun removeMsg(msgId: String): Boolean {
        return mqttMsgIdArray.remove(msgId)
    }


    override fun onDestroy() {
        super.onDestroy()
        NLog.e("[mqttv5] ***** mqtt client destroy ******")
        isTryingConnect = false
        _mqttBean = null
        notifyMqttStatus(4)
        isForegroundServiceStarted = false
        stopForeground(STOP_FOREGROUND_REMOVE)
        mHandler.removeMessages(MSG_RECONNECT)
        Module_Main_MqttUtils.destroy()
        _mRetryTime = 20
        mIsConnecting = false
        EventBus.getDefault().unregister(this)
        Module_Phone_VoipController.get().coreContext.core.removeListener(coreListener)
    }

    inner class MqttStatusListener : IMqttStatusListener {
        override fun connectSuccess(asyncActionToken: IMqttToken) {
            EnhancedLogger.success("MqttV5Service", "========== MQTT 连接成功 ==========")
            EnhancedLogger.success("MqttV5Service", "连接令牌: $asyncActionToken")
            EnhancedLogger.success("MqttV5Service", "客户端状态: ${Module_Main_MqttUtils.mqttV5Client?.isConnected}")
            EnhancedLogger.success("MqttV5Service", "连接耗时: ${System.currentTimeMillis() - lastConnectTime}ms")
            EnhancedLogger.success("MqttV5Service", "==================================")
            NLog.e("[mqttv5] >> connectSuccess")
            onNetworkLinkEstablished()
            notifyMqttStatus(2)
            isTryingConnect = false
            if (needDisconnectMqttV5) {
                needDisconnectMqttV5 = false
                NLog.e("[mqttv5] >> needDisconnectMqttV5 disConnect")
                MainScope().launch(Dispatchers.Main) {
                    try {
                        Module_Main_MqttUtils.destroy()
                        stopSelf()
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }
                }
            }

        }

        override fun connectFail(asyncActionToken: IMqttToken, exception: Throwable) {
            EnhancedLogger.e("MqttV5Service", "========== MQTT 连接失败 ==========")
            EnhancedLogger.e("MqttV5Service", "失败令牌: $asyncActionToken")
            EnhancedLogger.e("MqttV5Service", "异常信息: ${exception.message}")
            EnhancedLogger.e("MqttV5Service", "异常类型: ${exception.javaClass.simpleName}")
            EnhancedLogger.e("MqttV5Service", "MQTT URL: ${_mqttBean?.url}")
            EnhancedLogger.e("MqttV5Service", "用户名: ${_mqttBean?.userName}")
            EnhancedLogger.e("MqttV5Service", "客户端ID: ${_mqttBean?.userId}")
            EnhancedLogger.e("MqttV5Service", "连接耗时: ${System.currentTimeMillis() - lastConnectTime}ms")

            // 🔥 添加详细的异常堆栈信息
            EnhancedLogger.e("MqttV5Service", "异常堆栈:", exception)
            if (exception.cause != null) {
                EnhancedLogger.e("MqttV5Service", "根本原因: ${exception.cause?.javaClass?.simpleName}")
                EnhancedLogger.e("MqttV5Service", "根本原因消息: ${exception.cause?.message}")
            }

            // 特别处理 DNS 解析失败
            if (exception.cause is java.net.UnknownHostException) {
                EnhancedLogger.e("MqttV5Service", "⚠️ DNS解析失败！请检查：")
                EnhancedLogger.e("MqttV5Service", "  1. 设备网络连接是否正常")
                EnhancedLogger.e("MqttV5Service", "  2. DNS服务器设置是否正确")
                EnhancedLogger.e("MqttV5Service", "  3. 是否使用了VPN或代理")
                EnhancedLogger.e("MqttV5Service", "  4. 域名是否在内网环境")
            }

            EnhancedLogger.e("MqttV5Service", "==================================")
            NLog.e("[mqttv5] >> connectFail")
            onNetworkLinkFailed(asyncActionToken, exception)
            notifyMqttStatus(4)
            isTryingConnect = false
        }

        override fun unSubscribeSuccess(iMqttToken: IMqttToken) {
            NLog.e("[mqttv5] 取消订阅成功:$iMqttToken")
        }

        override fun unSubscribeFail(iMqttToken: IMqttToken?, throwable: Throwable?) {
            NLog.e("[mqttv5] 取消订阅失败$throwable")
        }

        override fun subscribeSuccess(iMqttToken: IMqttToken) {
            NLog.e("[mqttv5] 订阅成功:${iMqttToken}")
        }

        override fun subscribeFail(iMqttToken: IMqttToken, throwable: Throwable) {
            NLog.e("[mqttv5] 订阅失败$throwable")
        }

        override fun connectComplete(reconnect: Boolean, serverURI: String) {
            NLog.e("[mqttv5] connectComplete  reconnect=$reconnect")
            NLog.e("[mqttv5] connectComplete  serverURI=$serverURI")
            if (Module_Main_MqttUtils.isConnect() == false) {
                return
            }
            if (!reconnect) {
                return
            }
            Module_Main_MqttUtils.subscribeTopicList(mTopicList)
            LoopBackManager.get().nativeMqttRegStatus(1)
            EventBus.getDefault()
                .post(MessageEvent(TYPE_APP_MQTT_CHECK_STATE_CALLBACK, 1))
            notifyMqttStatus(2)

        }

        override fun connectLost(code: Int) {
            NLog.e("[mqttv5] connectLost  $code")
            notifyMqttStatus(4)
            onConnectMqttLost(code)
        }
    }

    private fun notifyMqttStatus(status: Int) {
        NLog.e("[mqttv5] >>>>  notifyMqttStatus status=$status")
        if (status == 2 && !mIsConnecting) {
            NLog.e("[mqttv5] >>>>  MQTT Connected..")
        }
        EventBus.getDefault().post(
            MessageEvent(
                TYPE_APP_MQTT_UPDATE_STATE,
                status
            )
        )
        mIsConnecting = status == 2
//        EventBus.getDefault().post(SipStateEvent(status))
    }


    private fun onNetworkLinkEstablished() {
        NLog.e("[mqttv5] onNetworkLinkEstablished")
        Module_Main_MqttUtils.subscribeTopicList(mTopicList)
        NLog.e("[mqttv5] subscribe topic :::>$mTopicList")
        mHandler.removeMessages(MSG_RECONNECT)
        _mRetryTime = 0
    }

    private fun onNetworkLinkFailed(asyncActionToken: IMqttToken, exception: Throwable) {
        NLog.e("[mqttv5] >>> connect failed IMqttToken:> ${asyncActionToken.exception}  >> ${asyncActionToken.message}")
        NLog.e("[mqttv5] >>> connect failed exception :> $exception")
        reconnectMqtt()
    }

    private fun onConnectMqttLost(code: Int) {
        NLog.e("[mqttv5] mqtt connect lost code=$code ")
        when (code) {
            401 -> return
            138 -> NLog.e("[mqttv5] >> receive 138 , connect mqtt server refused ")
            142 -> {
                NLog.e("[mqttv5] >> receive 142 , disconnect MQTT Server ")
                MainScope().launch {
                    delay(1000)
                    Module_Main_MqttUtils.destroy()
                    EventBus.getDefault().post(ExitByHttpEvent(1))
                    stopSelf()
                }
            }

            152 -> {
                NLog.e("[mqttv5] >> receive 152 , disconnect MQTT Server ")
                Module_Main_MqttUtils.destroy()
                EventBus.getDefault().post(ExitByHttpEvent(0))
                stopSelf()
            }

            else -> {
                // 0 正常退出
                reconnectMqtt()
            }
        }
    }

    /**
     * 开启前台服务 , 防止SERVICE被系统回收
     */
    private fun startMyForegroundService() {
        Log.d(TAG, "[mqttv5] >>> startForeground")
        val notification: Notification = createNotification()

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
            val mask = Module_Phone_Compatibility.FOREGROUND_SERVICE_TYPE_DATA_SYNC
            Module_Phone_Compatibility.startForegroundService(
                this,
                SERVICE_NOTIF_ID,
                notification,
                mask
            )
        } else {
            Module_Phone_Compatibility.startForegroundService(this, SERVICE_NOTIF_ID, notification)
        }
//        startForeground(FOREGROUND_ID, notification)
        isForegroundServiceStarted = true

    }

    private fun createNotification(): Notification {

        val serviceChannel =
            getString(com.newlink.building.R.string.notification_channel_service_id)

        if (Version.sdkAboveOrEqual(Version.API26_O_80)) {
            Api26Compatibility.createServiceChannel(this, NotificationManagerCompat.from(this))
        }

        val pendingIntent: PendingIntent =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                val postcard = ARouter.getInstance().build(Base_RouterPath.PATH_NOTIFY)
                LogisticsCenter.completion(postcard);
                Intent(applicationContext, postcard.destination).let {
                    PendingIntent.getActivity(
                        this, 0, it, PendingIntent.FLAG_IMMUTABLE
                    )
                }
            } else {
                val postcard = ARouter.getInstance().build(Base_RouterPath.PATH_NOTIFY)
                LogisticsCenter.completion(postcard);
                Intent(applicationContext, postcard.destination).let {
                    PendingIntent.getActivity(
                        this, 0, it, PendingIntent.FLAG_IMMUTABLE
                    )
                }
            }

        Log.d(TAG, "[mqttv5] >>> startForeground")

        val notification = NotificationCompat.Builder(this, serviceChannel)
            .setContentTitle(getString(com.newlink.building.R.string.app_name_smart))
            .setContentText(getString(com.newlink.building.R.string.service_description))
            .setSmallIcon(com.newlink.building.R.mipmap.logo)
            .setCategory(NotificationCompat.CATEGORY_SERVICE)
            .setVisibility(NotificationCompat.VISIBILITY_SECRET)
            .setWhen(System.currentTimeMillis())
            .setShowWhen(true)
            .setOngoing(true)
            .setColor(
                ContextCompat.getColor(
                    this,
                    com.newlink.building.R.color.colorPrimary
                )
            )
            .setContentIntent(pendingIntent).build()

        return notification
    }


    private fun connectToMqttService() {

        EnhancedLogger.i("MqttV5Service", "========== 开始 MQTT 连接流程 ==========")

        if (!isNetworkAvailable(applicationContext)) {
            EnhancedLogger.w("MqttV5Service", "网络不可用，无法连接 MQTT")
            NLog.e("[mqttv5] network error.!!!!")
            return
        }

        if (Module_Main_MqttUtils.isConnect() == true) {
            EnhancedLogger.i("MqttV5Service", "MQTT 已连接，跳过重复连接")
            NLog.e("[mqttv5] mqtt is connected .!!!!")
            return
        }

        if (isTryingConnect) {
            EnhancedLogger.w("MqttV5Service", "MQTT 正在连接中，跳过重复连接请求")
            return
        }

        // 🔥 添加DNS检查（异步执行，避免NetworkOnMainThreadException）
        _mqttBean?.url?.let { url ->
            val host = url.substringAfter("://").substringBefore(":")
            EnhancedLogger.i("MqttV5Service", "DNS检查：尝试解析 $host")
            MainScope().launch(Dispatchers.IO) {
                try {
                    val addresses = java.net.InetAddress.getAllByName(host)
                    withContext(Dispatchers.Main) {
                        EnhancedLogger.i("MqttV5Service", "✅ DNS解析成功：$host")
                        addresses.forEach {
                            EnhancedLogger.i("MqttV5Service", "  -> ${it.hostAddress}")
                        }
                    }
                } catch (e: java.net.UnknownHostException) {
                    withContext(Dispatchers.Main) {
                        EnhancedLogger.e("MqttV5Service", "❌ DNS解析失败: $host")
                        EnhancedLogger.e("MqttV5Service", "请检查：", e)
                        EnhancedLogger.e("MqttV5Service", "1. 设备网络设置")
                        EnhancedLogger.e("MqttV5Service", "2. DNS服务器：系统DNS或私有DNS")
                        EnhancedLogger.e("MqttV5Service", "3. 如果是内网域名，请使用内网DNS")
                        EnhancedLogger.e("MqttV5Service", "4. 或者使用IP地址代替域名")
                    }
                }
            }
        }

        val doorTopic = Module_Main_MainConstants.COMMAND_MQTT_SUBSCRIBE_TOPIC_DOOR.replace("+", "$userId")
        val notifyTopic = String.format(COMMAND_MQTT_SUBSCRIBE_TOPIC_NOTIFY, userId)
        val callTopic = String.format(COMMAND_MQTT_SUBSCRIBE_TOPIC_CALL_CREATE_CHANNEL_ACK, userId)
        val sipTopic = String.format(COMMAND_MQTT_SUBSCRIBE_TOPIC_CALL_SIP_ACK, agoraId)
        val callMessageTopic = String.format(COMMAND_MQTT_SUBSCRIBE_TOPIC_CALL_MESSAGE_ACK, agoraId)

        // 🔥 修复：清空旧主题列表，防止重复添加
        mTopicList.clear()
        mTopicList.add(doorTopic)
        mTopicList.add(notifyTopic)
        mTopicList.add(callTopic)
        mTopicList.add(sipTopic)
        mTopicList.add(callMessageTopic)

        EnhancedLogger.i("MqttV5Service", "========== MQTT 主题列表 ==========")
        EnhancedLogger.i("MqttV5Service", "Door Topic: $doorTopic")
        EnhancedLogger.i("MqttV5Service", "Notify Topic: $notifyTopic")
        EnhancedLogger.i("MqttV5Service", "Call Topic: $callTopic")
        EnhancedLogger.i("MqttV5Service", "SIP Topic: $sipTopic")
        EnhancedLogger.i("MqttV5Service", "Call Message Topic: $callMessageTopic")
        EnhancedLogger.i("MqttV5Service", "UserId: $userId, AgoraId: $agoraId")
        EnhancedLogger.i("MqttV5Service", "==================================")

        if (_mqttBean != null) {
            _mqttBean?.let {
                val uName = it.userName
                val mqttUserName = if (uName.contains("APP_")) {
                    uName
                } else {
                    "APP_$uName"
                }

                EnhancedLogger.i("MqttV5Service", "========== 最终连接参数 ==========")
                EnhancedLogger.i("MqttV5Service", "原始用户名: $uName")
                EnhancedLogger.i("MqttV5Service", "最终用户名: $mqttUserName")
                EnhancedLogger.i("MqttV5Service", "客户端ID: ${it.userId}")
                EnhancedLogger.i("MqttV5Service", "MQTT URL: ${it.url}")
                EnhancedLogger.i("MqttV5Service", "主题数量: ${mTopicList.size}")
                EnhancedLogger.i("MqttV5Service", "==================================")

                isTryingConnect = true
                Module_Main_MqttUtils.connect(
                    this,
                    "${it.userId}",
//                    arrayListOf(doorTopic, notifyTopic, callTopic, sipTopic),
                    mTopicList,
                    mqttUserName,
                    it.password,
                    it.url,
                    mMqttStatusListener,
                    this
                )
            }

            lastConnectTime = System.currentTimeMillis()
            EnhancedLogger.i("MqttV5Service", "MQTT 连接请求已发送，连接时间: $lastConnectTime")

        } else {
            EnhancedLogger.e("MqttV5Service", "MQTT 连接失败：mqttBean 为 null")
            NLog.e("[mqttv5] connectToMqttService mqttBean is null")
            EventBus.getDefault()
                .post(MessageEvent(TYPE_APP_MQTT_CHECK_STATE_CALLBACK, 0))
        }
    }

    override fun onTaskRemoved(rootIntent: Intent?) {
        super.onTaskRemoved(rootIntent)
        NLog.e("[mqttv5] >>> onTaskRemoved")

        if (Module_Phone_VoipController.get().getCallsNb() > 0) {
            if (!fromFcmCall) {
                NLog.e("[mqttv5] >>> Hang Up... ")
                Module_Phone_VoipController.get().hangUp()
            }
        }

    }

    fun saveLog(message: String, tag: String = "MQTT") {
        try {
            LogHandlerThread.instance?.writeLog(this, tag, message)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun appendLineBreak(count: Int = 1) {
        if (LogHandlerThread.instance?.isLogFileEmpty(this) == true) {
            return
        }
        LogHandlerThread.instance?.appendLineBreak(this, count)
    }
}
